package cz.vse.integrace.iag.synchronizace;

import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.extensions.City;
import com.google.gdata.data.extensions.Email;
import com.google.gdata.data.extensions.FamilyName;
import com.google.gdata.data.extensions.FullName;
import com.google.gdata.data.extensions.GivenName;
import com.google.gdata.data.extensions.Name;
import com.google.gdata.data.extensions.OrgDepartment;
import com.google.gdata.data.extensions.OrgTitle;
import com.google.gdata.data.extensions.Organization;
import com.google.gdata.data.extensions.PostCode;
import com.google.gdata.data.extensions.Street;
import com.google.gdata.data.extensions.StructuredPostalAddress;
import cz.vse.integrace.iag.db.Adresa;
import cz.vse.integrace.iag.db.ZamestnanciDAO;
import cz.vse.integrace.iag.db.Oddeleni;
import cz.vse.integrace.iag.db.Zamestnanec;
import cz.vse.integrace.iag.google.KontaktyDAO;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;

/**
 * Stateless bean sloužící pro synchrnonizaci zaměstnaců z SQL Databáze 
 * a kontaktů z Google kontakty.
 * 
 * @author David Nejedly
 * @version 1.0
 */
@Stateless
public class SynchronizaceBean implements Synchronizace {

    @EJB
    private ZamestnanciDAO zamestnanciDAO;
    @EJB
    private KontaktyDAO kontaktyDAO;
    private static final Logger LOGGER = Logger.getLogger(SynchronizaceBean.class.getCanonicalName());

    /**
     * Metoda provádějící synchronizaci.
     * Obsahuje logiku synchronizace, co, kam a odkud má být synchronizováno.
     * 
     * @return true, pokud byla synchronizace úspěšná, jinak false
     */
    @Override
    public boolean synchronizace() {
        boolean synchronizovano = true;
        Map<String, byte[]> fotky = new HashMap<String, byte[]>();
        List<Oddeleni> oddeleni = zamestnanciDAO.getOddeleni();
        for (Oddeleni odd : oddeleni) {
            for (Zamestnanec zam : odd.getZamestnanci()) {
                ContactEntry kontakt = null;
                boolean maPracovniAdresu = false;
                boolean maPracovniEmail = false;
                boolean maOrganizaci = false;
                if (zam.getKontaktId() != null) {
                    //Získání pocmocí tokenu nebo hesla
                    kontakt = kontaktyDAO.getKontakt(zam.getEmailPrace(), zam.getAccessToken(), zam.getHeslo(), zam.getKontaktId());
                    if (kontakt != null) {
                        //Načtení kontaktů
                        zam.setKontakty(kontaktyDAO.getKontatky(zam.getEmailPrace(), zam.getAccessToken(), zam.getHeslo()));
                        //Fyzické adresy
                        if (kontakt.hasStructuredPostalAddresses()) {
                            for (StructuredPostalAddress postovniAdresa : kontakt.getStructuredPostalAddresses()) {
                                if (StructuredPostalAddress.Rel.WORK.equals(postovniAdresa.getRel())) {
                                    if (zam.getPrace() == null) {
                                        zam.setPrace(new Adresa());
                                    }
                                    synchAdresa(zam.getPrace(), postovniAdresa);
                                    postovniAdresa.setPrimary(Boolean.TRUE);
                                    postovniAdresa.setRel(StructuredPostalAddress.Rel.WORK);
                                    maPracovniAdresu = true;
                                } else if (StructuredPostalAddress.Rel.HOME.equals(postovniAdresa.getRel())) {
                                    if (zam.getDoma() == null) {
                                        zam.setDoma(new Adresa());
                                    }
                                    synchAdresa(zam.getDoma(), postovniAdresa);
                                    postovniAdresa.setPrimary(Boolean.FALSE);
                                    postovniAdresa.setRel(StructuredPostalAddress.Rel.HOME);
                                }
                            }
                        }
                        byte[] fotka = kontaktyDAO.nactiFoto(zam.getEmailPrace(), zam.getAccessToken(), zam.getHeslo(), kontakt);
                        //Foto účtu
                        zam.setFotka(fotka);
                        if (zam.getFotka() != null) {
                            fotky.put(zam.getEmailPrace(), zam.getFotka());
                        }
                        //Načtení domácí adresy
                        if (kontakt.hasEmailAddresses()) {
                            for (Email email : kontakt.getEmailAddresses()) {
                                if (Email.Rel.HOME.equals(email.getRel())) {
                                    zam.setEmailDoma(email.getAddress());
                                    email.setPrimary(Boolean.FALSE);
                                    email.setRel(Email.Rel.HOME);
                                } else if (Email.Rel.WORK.equals(email.getRel())) {
                                    //Pracovní email je vždy přepsán
                                    email.setAddress(zam.getEmailPrace());
                                    email.setRel(Email.Rel.WORK);
                                    email.setPrimary(true);
                                    maPracovniEmail = true;
                                }
                            }
                        }
                        if (kontakt.hasOrganizations()) {
                            for (Organization organizace : kontakt.getOrganizations()) {
                                if (organizace.hasOrgDepartment() && organizace.getOrgDepartment().getValue().equals(odd.getNazev())) {
                                    organizace.setOrgTitle(new OrgTitle(zam.getPozice()));
                                    maOrganizaci = true;
                                }
                            }
                        }
                    }
                }
                if (kontakt == null) {
                    kontakt = new ContactEntry();
                }
                //Přidání pracovní adresy pokud žádnou nemá
                if (!maPracovniAdresu) {
                    StructuredPostalAddress novaPracovniAdresa = new StructuredPostalAddress();
                    novaPracovniAdresa.setRel(StructuredPostalAddress.Rel.WORK);
                    synchAdresa(zam.getPrace(), novaPracovniAdresa);
                    kontakt.addStructuredPostalAddress(novaPracovniAdresa);
                }
                //Jméno je vždy přepsnáno
                Name jmeno = new Name();
                jmeno.setFullName(new FullName(zam.getCeleJmeno(), null));
                jmeno.setGivenName(new GivenName(zam.getJmeno(), null));
                jmeno.setFamilyName(new FamilyName(zam.getPrijmeni(), null));
                kontakt.setName(jmeno);
                //Předání pracovního emailu pokud ho nemá
                if (!maPracovniEmail) {
                    Email praceEmail = new Email();
                    praceEmail.setAddress(zam.getEmailPrace());
                    praceEmail.setRel(Email.Rel.WORK);
                    praceEmail.setPrimary(true);
                    kontakt.addEmailAddress(praceEmail);
                }
                //Nastavení organizace
                if (!maOrganizaci) {
                    Organization organizace = new Organization();
                    organizace.setOrgDepartment(new OrgDepartment(odd.getNazev()));
                    organizace.setOrgTitle(new OrgTitle(zam.getPozice()));
                    organizace.setRel(Organization.Rel.WORK);
                    kontakt.addOrganization(organizace);
                }
                LOGGER.fine("před uložením kontaktu");
                //Uložení kontaktu
                kontakt = kontaktyDAO.ulozKontakt(kontakt, zam.getEmailPrace(), zam.getAccessToken(), zam.getHeslo());
                if (kontakt != null) {
                    zam.setKontaktId(kontakt.getId());
                    for (Oddeleni oddel : oddeleni) {
                        for (Zamestnanec zamestnanec : oddel.getZamestnanci()) {
                            if (!zamestnanec.equals(zam)) {
                                kontakt.setId(null);
                                kontakt.removeLinks();
                                kontakt.setCanEdit(false);
                                zamestnanec.addKontakt(kontakt);
                            }
                        }
                    }
                } else {
                    synchronizovano = false;
                }
            }

        }
        for (Oddeleni odd : oddeleni) {
            for (Zamestnanec zam : odd.getZamestnanci()) {
                zamestnanciDAO.ulozZamestnance(zam);
                kontaktyDAO.setKontakty(zam.getEmailPrace(), zam.getAccessToken(), zam.getHeslo(), zam.getKontakty(), fotky);
            }
        }


        return synchronizovano;

    }

    /**
     * Metoda synchronizující adresu z databáze a adresu z google kontaktů
     * 
     * @param adresa adresa z databáze
     * @param postovniAdresa adresa z google kontaků
     */
    private void synchAdresa(Adresa adresa, StructuredPostalAddress postovniAdresa) {
        if (adresa == null || postovniAdresa == null) {
            LOGGER.log(Level.WARNING, "Adresa je {0}. Postovni adresa je{1}.", new Object[]{adresa, postovniAdresa});
        }
        //Ulice a číslo popisné
        if (adresa.getUlice() == null || adresa.getUlice().isEmpty()) {
            if (postovniAdresa.hasStreet() && postovniAdresa.getStreet().hasValue()) {
                String[] slovaAdresy = postovniAdresa.getStreet().getValue().split(" ");
                String cp = null;
                if (slovaAdresy.length > 1) {
                    cp = slovaAdresy[slovaAdresy.length - 1];
                    if (cp.contains("/")) {
                        cp = cp.split("/")[0];
                    }
                    boolean cpCislo = false;
                    try {
                        adresa.setCisloPopisne(Integer.parseInt(cp));
                        cpCislo = true;
                    } catch (NumberFormatException e) {
                        LOGGER.log(Level.WARNING, "Není číslo: " + cp, e);
                    }
                    StringBuilder ulice = new StringBuilder();
                    int delkaPole = 0;
                    if (cpCislo) {
                        delkaPole = slovaAdresy.length - 1;
                    } else {
                        delkaPole = slovaAdresy.length;
                    }
                    for (int i = 0; i < delkaPole; i++) {
                        ulice.append(slovaAdresy[i]);
                        if (delkaPole - 1 != i) {
                            ulice.append(" ");
                        }
                    }
                    adresa.setUlice(ulice.toString());
                } else {
                    adresa.setUlice(postovniAdresa.getStreet().getValue());
                }
            }
        } else {
            postovniAdresa.setStreet(new Street(adresa.getUlice() + " " + adresa.getCisloPopisne()));
        }
        //Mesto
        if (adresa.getMesto() == null || adresa.getMesto().isEmpty()) {
            if (postovniAdresa.hasCity() && postovniAdresa.getCity().hasValue()) {
                adresa.setMesto(postovniAdresa.getCity().getValue());
            }
        } else {
            postovniAdresa.setCity(new City(adresa.getMesto()));
        }
        //PSC
        if (adresa.getPsc() <= 0) {
            if (postovniAdresa.hasPostcode() && postovniAdresa.getPostcode().hasValue()) {
                try {
                    adresa.setPsc(Integer.parseInt(postovniAdresa.getPostcode().getValue()));
                } catch (NumberFormatException e) {
                    LOGGER.log(Level.WARNING, "Není číslo: " + postovniAdresa.getHousename().getValue(), e);
                }
            }
        } else {
            postovniAdresa.setPostcode(new PostCode("" + adresa.getPsc()));
        }
    }
}